package com.ukefu.webim.web.handler.apps.internet;

import com.ukefu.core.UKDataContext;
import com.ukefu.util.Menu;
import com.ukefu.util.UKTools;
import com.ukefu.util.client.UserClient;
import com.ukefu.webim.service.cache.CacheHelper;
import com.ukefu.webim.service.repository.SNSAccountRepository;
import com.ukefu.webim.service.repository.WeiXinUserRepository;
import com.ukefu.webim.util.weixin.config.WechatMpConfiguration;
import com.ukefu.webim.util.weixin.config.WechatOpenConfiguration;
import com.ukefu.webim.util.weixin.config.WeiXinConfiguration;
import com.ukefu.webim.web.model.SNSAccount;
import com.ukefu.webim.web.model.SystemConfig;
import com.ukefu.webim.web.model.WeiXinUser;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/im/weixin/{snsid}")
public class UCKeFuWeiXinController {
	
	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	private WechatMpConfiguration mpconfig = WechatMpConfiguration.getInstance();
	
	@Autowired
	private WeiXinUserRepository weiXinUserRes ;

	@GetMapping(produces = "text/plain;charset=utf-8")
	@Menu(type = "wx" , subtype = "sns" , access = true)
	public String authGet(
			@RequestParam(name = "signature",
			required = false) String signature,
			@RequestParam(name = "timestamp",
			required = false) String timestamp,
			@RequestParam(name = "nonce", required = false) String nonce,
			@RequestParam(name = "echostr", required = false) String echostr , @PathVariable String snsid) {
		SystemConfig systemConfig = (SystemConfig) CacheHelper.getSystemCacheBean().getCacheObject("systemConfig", UKDataContext.SYSTEM_ORGI);

		//第三方平台授权
		boolean isAuth = false;
		SNSAccountRepository snsAccountRepository = UKDataContext.getContext().getBean(SNSAccountRepository.class);
		//由于无法提前知道租户id，不用orgi查询
		//SNSAccount snsAccount = snsAccountRepository.findBySnsidAndOrgi(snsid,UKDataContext.SYSTEM_ORGI);
		SNSAccount snsAccount = snsAccountRepository.findBySnsid(snsid);
		if(snsAccount == null){
			//第三方平台授权
			snsAccount = snsAccountRepository.findByAppkey(snsid);
			//snsAccount = snsAccountRepository.findByAppkeyAndOrgi(snsid,UKDataContext.SYSTEM_ORGI);
			if(snsAccount != null){
				snsid = snsAccount.getSnsid();
				isAuth = true;
			}
		}

		if(systemConfig!=null && "debug".equals(systemConfig.getLoglevel())){
			this.logger.info("\n接收到来自微信服务器的认证消息：[{},{}, {}, {}, {}]",snsid , signature,
		            timestamp, nonce, echostr);
		}
		if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
			echostr = "0" ;
		}
		WeiXinConfiguration weiXinConfigure = this.mpconfig.getConfiguration(snsid) ;
		if(weiXinConfigure!=null){
			if(isAuth){
				if (!WechatOpenConfiguration.getInstance().getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) {
					throw new IllegalArgumentException("非法请求，可能属于伪造的请求！");
				}
			}else{
				if (!weiXinConfigure.getService().checkSignature(timestamp, nonce, signature)) {
					throw new IllegalArgumentException("非法请求，可能属于伪造的请求！");
				}
			}
		}
		return echostr;
	}

	@Menu(type = "wx" , subtype = "sns" , access = true)
	@PostMapping(produces = "application/xml; charset=UTF-8")
	public String post(@RequestBody String requestBody,
			@RequestParam("signature") String signature,
			@RequestParam("timestamp") String timestamp,
			@RequestParam("nonce") String nonce,
			@RequestParam(name = "encrypt_type",
			required = false) String encType,
			@RequestParam(name = "msg_signature",
			required = false) String msgSignature , @PathVariable String snsid) throws WxErrorException {

		//第三方平台授权
		boolean isAuth = false;
		SystemConfig systemConfig = (SystemConfig) CacheHelper.getSystemCacheBean().getCacheObject("systemConfig", UKDataContext.SYSTEM_ORGI);
		SNSAccountRepository snsAccountRepository = UKDataContext.getContext().getBean(SNSAccountRepository.class);
		//由于无法提前知道租户id，不用orgi查询
		//SNSAccount snsAccount = snsAccountRepository.findBySnsidAndOrgi(snsid,UKDataContext.SYSTEM_ORGI);
		SNSAccount snsAccount = snsAccountRepository.findBySnsid(snsid);
		String appid = snsid;
		if(snsAccount == null){
			//第三方平台授权
			snsAccount = snsAccountRepository.findByAppkey(snsid);
			//snsAccount = snsAccountRepository.findByAppkey(snsid,UKDataContext.SYSTEM_ORGI);
			if(snsAccount != null){
				snsid = snsAccount.getSnsid();
				isAuth = true;
			}
		}
		WeiXinConfiguration weiXinConfigure = this.mpconfig.getConfiguration(snsid) ;
		if(systemConfig!=null && "debug".equals(systemConfig.getLoglevel())){
			this.logger.info(
	            "\n接收微信请求：[said=[{}] , weiXinConfigure = [{}],signature=[{}], encType=[{}], msgSignature=[{}],"
	                + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
	            snsid , weiXinConfigure ,signature, encType, msgSignature, timestamp, nonce, requestBody);
		}

		String out = null;
		WxMpXmlMessage inMessage = null ;

		//自定义参数
		Map<String, Object> context = new HashMap<>();
		context.put("snsid",snsid);

		if(weiXinConfigure!=null){

			if(isAuth){
				if (!WechatOpenConfiguration.getInstance().getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) {
					throw new IllegalArgumentException("非法请求，可能属于伪造的请求！");
				}
			}else{
				if (!weiXinConfigure.getService().checkSignature(timestamp, nonce, signature)) {
					throw new IllegalArgumentException("非法请求，可能属于伪造的请求！");
				}
			}

			if (encType == null) {
				// 明文传输的消息
				inMessage = WxMpXmlMessage.fromXml(requestBody);
				if (systemConfig != null && "debug".equals(systemConfig.getLoglevel())) {
					this.logger.info("\n消息内容为：\n{} ", inMessage.toString());
				}
				processWeiXinUser(inMessage, weiXinConfigure, snsid , weiXinConfigure.getSnsAccount().getOrgi());
				if(isAuth) {
					inMessage = WxOpenXmlMessage.fromEncryptedMpXml(requestBody,
							WechatOpenConfiguration.getInstance().getWxOpenConfigStorage(), timestamp, nonce, msgSignature);

					WxMpXmlOutMessage outMessage = WechatOpenConfiguration.getInstance().getWxOpenMessageRouter().route(inMessage,context, appid);
					if(outMessage != null){
						out = outMessage.toXml();
					}else{
						out ="";
					}
				}else{
					WxMpXmlOutMessage outMessage = weiXinConfigure.getRouter().route(inMessage,context) ;

					if (outMessage == null) {
						out = "";
					}else{
						out = outMessage.toXml();
					}
				}
			} else if ("aes".equals(encType)) {
				if(isAuth) {
					inMessage = WxOpenXmlMessage.fromEncryptedMpXml(requestBody,
							WechatOpenConfiguration.getInstance().getWxOpenConfigStorage(), timestamp, nonce, msgSignature);
					if(systemConfig!=null && "debug".equals(systemConfig.getLoglevel())){
						this.logger.info("\n消息解密后内容为：\n{} ", inMessage.toString());
					}
					processWeiXinUser(inMessage, weiXinConfigure, snsid , weiXinConfigure.getSnsAccount().getOrgi());
					WxMpXmlOutMessage outMessage = WechatOpenConfiguration.getInstance().getWxOpenMessageRouter().route(inMessage,context, appid);
					if(outMessage != null){
						out = WxOpenXmlMessage.wxMpOutXmlMessageToEncryptedXml(outMessage, WechatOpenConfiguration.getInstance().getWxOpenConfigStorage());
					}
				}else{
					// aes加密的消息
					inMessage = WxMpXmlMessage.fromEncryptedXml(
							requestBody, weiXinConfigure.getService().getWxMpConfigStorage(), timestamp,
							nonce, msgSignature);
					if(systemConfig!=null && "debug".equals(systemConfig.getLoglevel())){
						this.logger.info("\n消息解密后内容为：\n{} ", inMessage.toString());
					}
					processWeiXinUser(inMessage, weiXinConfigure, snsid , weiXinConfigure.getSnsAccount().getOrgi());
					WxMpXmlOutMessage outMessage = weiXinConfigure.getRouter().route(inMessage,context) ;
					if (outMessage == null) {
						out = "";
					}else{
						out = outMessage.toEncryptedXml(weiXinConfigure.getService().getWxMpConfigStorage());
					}
				}
			}
		}
		if(systemConfig!=null && "debug".equals(systemConfig.getLoglevel())){
			this.logger.info("\n输出内容为：\n{} ", out);
		}
		return out;
	}
	
	private void processWeiXinUser(WxMpXmlMessage inMessage , WeiXinConfiguration weiXinConfigure , String snsid , String orgi) throws WxErrorException{
		String openid = inMessage.getFromUser() ;
		//微信粉丝key openid + _ + snsid
		String key = openid + "_" + snsid;
		if(!UserClient.getUserClientMap().containsKey(key)){
			List<WeiXinUser> weiXinUserList = weiXinUserRes.findByOpenidAndSnsidAndOrgi(openid , snsid,orgi) ;
			WeiXinUser weiXinUser = null ;
			if(weiXinUserList.size()>0){
				weiXinUser = weiXinUserList.get(0) ;
			}else{
				WxMpUser wxUser = weiXinConfigure.getService().getUserService().userInfo(openid) ;
				if(wxUser != null){
					UKTools.copyProperties(wxUser, weiXinUser = new WeiXinUser());
					try {
						weiXinUser.setNickname(UKTools.filterOffUtf8Mb4(wxUser.getNickname()));
					} catch (UnsupportedEncodingException e) {
						e.printStackTrace();
					}
					weiXinUser.setSex(wxUser.getSexDesc());
					weiXinUser.setSexid(wxUser.getSex());
					weiXinUser.setHeadimgurl(wxUser.getHeadImgUrl());
					weiXinUser.setOpenid(wxUser.getOpenId());
					weiXinUser.setGroupid(wxUser.getGroupId());
					weiXinUser.setSnsid(snsid);
					weiXinUser.setOrgi(orgi);
					weiXinUser.setSubscribetime(String.valueOf(wxUser.getSubscribeTime()));
					
					if(!StringUtils.isBlank(weiXinConfigure.getSnsAccount().getAppkey())){
						weiXinUser.setAppid(weiXinConfigure.getSnsAccount().getAppkey());
					}
					
					if(weiXinUserRes.countByOpenidAndSnsidAndOrgi(wxUser.getOpenId(), snsid,orgi) == 0){
						weiXinUserRes.save(weiXinUser) ;
					}
				}
			}
			UserClient.getUserClientMap().put(key, weiXinUser) ;
		}
	}
}